#ifndef SSL_CONNECTION_H
#define SSL_CONNECTION_H

#include <memory>

// #include "../../../tcp/code/utility/Noncopyable.h"
#include "../../../tcp/code/reactor/TcpConnection.h"
#include "../../../tcp/code/utility/Buffer.h"
#include "./SslContext.h"

class SslConnection : Noncopyable
{
public:
    using TcpConnectionPtr = std::shared_ptr<TcpConnection>;
    using MessageCallback = std::function<void(const std::shared_ptr<TcpConnection> &,
                                               Buffer *,
                                               Timestamp)>;

    SslConnection(const TcpConnectionPtr &tcpConn, SslContext *sslCtx);
    ~SslConnection();

    void setMessageCallback(const MessageCallback &cb)
    {
        this->messageCallback_ = std::move(cb);
    }
    void startHandshake();
    void onRead(const TcpConnectionPtr &conn, Buffer *buf, Timestamp time);
    bool isHandshakeCompleted() const
    {
        return this->sslState_ == SslState::Established;
    }
    Buffer *getDecryptedBuffer()
    {
        return &this->decryptedBuffer_;
    }

    // 暂时未用
    static BIO_METHOD *createCustomBioMethod(); // 未用，用的是标准内存BIO
    // BIO操作回调，注册后OpenSSL会自动调用，签名固定，内容用户实现
    static int bioRead(BIO *bio, char *data, int len);
    static int bioWrite(BIO *bio, const char *data, int len);
    static long bioCtrl(BIO *bio, int cmd, long num, void *ptr);

private:
    void handleHandshake();

    // 暂时未用
    void onEncrypted(const char *data, size_t len);
    void onDecrypted(const char *data, size_t len);
    SslError getLastError(int ret);
    void handleError(SslError error);
    void send(const void *data, size_t len);

private:
    TcpConnectionPtr tcpConn_;
    SslContext *sslCtx_;

    SSL *sslConn_;
    SslState sslState_ = SslState::Handshake;

    // BIO（Basic I/O）：通用IO抽象层，处理加解密IO
    BIO *readBio_;                    // 网络数据 -> SSL
    BIO *writeBio_;                   // SSL -> 网络数据
    Buffer decryptedBuffer_;          // 解密后的数据
    MessageCallback messageCallback_; // 消息回调

    // 暂时未用
    Buffer readBuffer_;  // 读缓冲区
    Buffer writeBuffer_; // 写缓冲区
};

#endif // SSL_CONNECTION_H